package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.business.api.RemoteDestinationService;
import cn.wolfcode.wolf2w.business.api.domain.Destination;
import cn.wolfcode.wolf2w.business.api.domain.Note;

import cn.wolfcode.wolf2w.business.api.domain.NoteContent;
import cn.wolfcode.wolf2w.business.mapper.NoteMapper;
import cn.wolfcode.wolf2w.business.query.NoteQuery;

import cn.wolfcode.wolf2w.business.service.INoteContentService;
import cn.wolfcode.wolf2w.business.service.INoteService;

import cn.wolfcode.wolf2w.business.util.DateUtil;
import cn.wolfcode.wolf2w.common.core.constant.SecurityConstants;
import cn.wolfcode.wolf2w.common.core.context.SecurityContextHolder;
import cn.wolfcode.wolf2w.common.redis.service.RedisService;
import cn.wolfcode.wolf2w.common.redis.util.RedisKeys;
import cn.wolfcode.wolf2w.member.api.RemoteUserInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * 旅游日记Service业务层处理
 *
 * @author zty
 * @date 2025-09-16
 */
@Service
@Transactional
public class NoteServiceImpl extends ServiceImpl<NoteMapper, Note> implements INoteService {
    @Autowired
    private RemoteUserInfoService remoteUserInfoService;
    @Autowired
    private INoteContentService noteContentService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RemoteDestinationService remoteDestinationService;

    @Override
    public IPage<Note> queryPage(NoteQuery qo) {

        IPage<Note> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());

        QueryWrapper queryWrapper = new QueryWrapper<>();

        if (qo.getOrderBy()==null){

            return baseMapper.selectPage(page, queryWrapper);
        }
        queryWrapper.eq("status",Note.STATE_RELEASE);
        /*最新/最热游记*/
        if (qo.getOrderType() == 2 || qo.getOrderBy().equals("create_time")) {
            //最热
            queryWrapper.orderByDesc("create_time");
        } else {
            //最新
            queryWrapper.orderByDesc("viewnum");
        }
        /*出发时间*/
        switch (qo.getTravelTimeType()) {
            case -1:
                //未选择
                break;
            case 1:
                //1-2月
                queryWrapper.apply("MONTH(travel_time) BETWEEN 1 AND 2");
                break;
            case 2:
                //3-4月
                queryWrapper.apply("MONTH(travel_time) BETWEEN 3 AND 4");
                break;
            case 3:
                //5-6月
                queryWrapper.apply("MONTH(travel_time) BETWEEN 5 AND 6");
                break;
            case 4:
                //7-8月
                queryWrapper.apply("MONTH(travel_time) BETWEEN 7 AND 8");
                break;
            case 5:
                //9-10月
                queryWrapper.apply("MONTH(travel_time) BETWEEN 9 AND 10");
                break;
            case 6:
                //11-12月
                queryWrapper.apply("MONTH(travel_time) BETWEEN 11 AND 12");
                break;
            default:
                break;
        }
        /*人均花费*/
        switch (qo.getConsumeType()) {
            case -1:
                //不限
                break;
            case 1:
                //1-999
                queryWrapper.apply("avg_consume BETWEEN 1 AND 999");
                break;
            case 2:
                //1k-6k
                queryWrapper.apply("avg_consume BETWEEN 1000 AND 6000");
                break;
            case 3:
                //6k-20k
                queryWrapper.apply("avg_consume BETWEEN 6000 AND 20000");
                break;
            case 4:
                //大于20k
                queryWrapper.apply("avg_consume >20000");
                break;
            default:
                break;
        }
        /*出行天数*/
        switch (qo.getDayType()) {
            case -1:
                //不限
                break;
            case 1:
                //1-3天
                queryWrapper.apply("days BETWEEN 1 AND 3");
                break;
            case 2:
                //4-7天
                queryWrapper.apply("days BETWEEN 4 AND 7");
                break;
            case 3:
                //8-14天
                queryWrapper.apply("days BETWEEN 8 AND 14");
                break;
            case 4:
                //15天以上
                queryWrapper.apply("days >15");
                break;
            default:
                break;
        }
        IPage iPage = baseMapper.selectPage(page, queryWrapper);
        iPage.getRecords().forEach(record -> {
            /*类型转换*/
            Note note = (Note) record;
            /*查询作者id*/
            note.setAuthor(remoteUserInfoService.getOne(note.getAuthorId(), SecurityConstants.INNER).getData());
        });
        return iPage;
    }

    @Override
    public Note getcontentById(Long id) {
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        Note note = baseMapper.selectOne(queryWrapper);
        note.setAuthor(remoteUserInfoService.getOne(note.getAuthorId(), SecurityConstants.INNER).getData());
        note.setContent(noteContentService.getById(note.getId()));
        return note;
    }

    @Override
    public List<Note> viewnnumTop3(Long destId) {
        List<Note> list = lambdaQuery().orderByDesc(Note::getViewnum)
                .eq(Note::getDestId, destId)
                .last("limit 3").list();
        return list;
    }

    /*浏览量++*/
    @Override
    public Map<String, Object> viewnumIncr(Long notId) {
        String key = noteHashInit(notId);
        redisService.incrementCacheMapValue(key, "viewnum", 1);
        Map<String, Object> cacheMap = redisService.getCacheMap(key);
        return cacheMap;
    }

    /*游记数据的持久化*/
    @Override
    public void noteStrategyNoteHashPersistence() {
        //找前缀
        String hashkey = RedisKeys.NOTE_STATIS_HASH.join("*");
        //查出指定前缀的数据存进一个集合中
        Collection<String> keys = redisService.keys(hashkey);
        if (keys != null && !keys.isEmpty()) {
            for (String key : keys) {
                Map<String, Object> cacheMap = redisService.getCacheMap(key);
                lambdaUpdate().eq(Note::getId, cacheMap.get("id"))
                        .set(Note::getViewnum, cacheMap.get("viewnum"))
                        .set(Note::getReplynum, cacheMap.get("replynum"))
                        .set(Note::getSharenum, cacheMap.get("sharenum"))
                        .set(Note::getFavornum, cacheMap.get("favornum"))
                        .set(Note::getThumbsupnum, cacheMap.get("thumbsupnum"))
                        .update();
            }
        }
    }

    @Override
    public Map<String, Object> collect(Long noteId) {
        Long userId = SecurityContextHolder.getUserId();
        //构建用户收藏key
        String key = RedisKeys.USER_NOTE_COLLECT.join(userId.toString());
        if (!redisService.hasKey(key)) {
            //用户没有收藏过--创建一个
            Set<Long> noteIds = new HashSet<>();
            //创建一个防止被删
            noteIds.add(-1l);
            redisService.setCacheSet(key, noteIds);

        }
        //获取这个游记的各种统计数据
        String hashkey = RedisKeys.NOTE_STATIS_HASH.join(noteId.toString());
        boolean isCollect = false;
        if (redisService.isCacheSetContains(key, noteId)) {
            //收藏过--数量减一
            redisService.incrementCacheMapValue(hashkey, "favornum", -1);
            //删除
            redisService.deleteCacheSetValue(key, noteId);
        } else {
            //没有收藏过--数量加一
            redisService.incrementCacheMapValue(hashkey, "favornum", 1);
            //添加
            redisService.addCacheSetValue(key, noteId);
            isCollect = true;
        }
        Map<String, Object> cacheMap = redisService.getCacheMap(hashkey);
        cacheMap.put("result", isCollect);


        return cacheMap;
    }

    /*判断是否是用户收藏*/
    @Override
    public Boolean isUserFavor(Long uid, Long noteId) {
        /*判断redis中是否有此用户收藏的攻略*/
        String redisKeys = RedisKeys.USER_NOTE_COLLECT.join(uid.toString());
        //判断redis中是否已经存在此用户收藏的攻略key--如果不存在创建一个 key--初始化
        if (!redisService.hasKey(redisKeys)) {
            //redis中没查到改用户对应的key--即用户没有收藏过
            Set<Long> sids = new HashSet<>();
            //添加一个-1防止集合被清除：-1不影响
            sids.add(-1l);
            redisService.setCacheSet(redisKeys, sids);
            /*redis中集合的特性：
             * 集合中必须至少有一个数据，如果没有数据，会被清掉
             * */
        }

        return redisService.isCacheSetContains(redisKeys, noteId);

    }

    /*点赞一天上限3个*/
    @Override
    public Map<String, Object> star(Long noteId) {
        //获取当前用户id
        Long userId = SecurityContextHolder.getUserId();
        //创建拼接noteid和uid的key
        String key = RedisKeys.USER_NOTE_COLLECT.join(noteId.toString(), userId.toString());
        //距离下一次零点的秒数--过期时间
        Date now = new Date();
        Date end = DateUtil.getLastMinuteOfDay(now);
        long time = DateUtil.getDateBetween(now, end);
        if (!redisService.hasKey(key)) {
            //如果redis中没有此key--创建一个
            redisService.setCacheObject(key, 0, time, TimeUnit.SECONDS);
        }
        //点赞次数加一
        Long ret = redisService.incrementCacheObjectValue(key, 1);
        boolean isThumbsUp = false;
        //实际统计数据
        String hashkey = RedisKeys.NOTE_STATIS_HASH.join(noteId.toString());
        if (ret <= 3) {
            isThumbsUp = true;
            redisService.incrementCacheMapValue(hashkey, "thumbsupnum", 1);
        }
        Map<String, Object> cacheMap = redisService.getCacheMap(hashkey);
        cacheMap.put("result", isThumbsUp);

        return cacheMap;
    }

    /*添加游记*/
    @Transactional
    @Override
    public void add(Note note) {
        Note finallynote = new Note();
        finallynote.setDestId(note.getDestId());
        Destination destination = remoteDestinationService.getOne(note.getDestId(), SecurityConstants.INNER).getData();
        finallynote.setDestName(destination.getName());
        finallynote.setAuthorId(SecurityContextHolder.getUserId());
        finallynote.setTitle(note.getTitle());
        finallynote.setSummary(note.getSummary());
        finallynote.setCoverUrl(note.getCoverUrl());
        finallynote.setTravelTime(note.getTravelTime());
        finallynote.setAvgConsume(note.getAvgConsume());
        finallynote.setDays(note.getDays());
        finallynote.setPerson(note.getPerson());
        finallynote.setReleaseTime(null);
        String temp = note.getIsPublic().equals("true") ? "1" : "0";
        finallynote.setIsPublic(temp);
        finallynote.setViewnum(0L);
        finallynote.setReplynum(0L);
        finallynote.setFavornum(0L);
        finallynote.setSharenum(0L);
        finallynote.setThumbsupnum(0L);
        finallynote.setStatus("0");
        finallynote.setCreateTime(new Date());
        finallynote.setUpdateTime(null);


        baseMapper.insert(finallynote);


        NoteContent noteContent = new NoteContent();
        noteContent.setId(finallynote.getId());
        noteContent.setContent(note.getContentStr());
        noteContentService.save(noteContent);


    }

    /*查询我的游记*/
    @Override
    public IPage<Note> queryMyNotePage(NoteQuery qo) {
        IPage<Note> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        Long userId = SecurityContextHolder.getUserId();
        QueryWrapper<Note> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("author_id", userId);
        return baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    public List<Note> viewnnumTop5() {
        return lambdaQuery().orderByDesc(Note::getCreateTime)
                .last("limit 5")
                .list();
    }

    @Override
    public NoteContent getcontentById2(Long id) {
        return noteContentService.getById(id);
    }


    /*数据redis预热*/
    private String noteHashInit(Long notId) {
        /*存储当前攻略的key*/
        String key = RedisKeys.NOTE_STATIS_HASH.join(notId.toString());
        if (!redisService.hasKey(key)) {
            /*当出现及特殊情况，redis服务器挂掉--查询mysql数据库*/
            Note note = this.getById(notId);

            Map<String, Object> map = new HashMap<>();
            map.put("viewnum", Integer.valueOf(note.getViewnum().toString()));
            /*数据库类型是Long数据带l，redis存储的时候带l，redis取数据带l可以正常识别，但是带l进行++操作会识别成字符串报错*/
            map.put("replynum", Integer.valueOf(note.getReplynum().toString()));
            map.put("sharenum", Integer.valueOf(note.getSharenum().toString()));
            map.put("favornum", Integer.valueOf(note.getFavornum().toString()));
            map.put("thumbsupnum", Integer.valueOf(note.getThumbsupnum().toString()));
            map.put("id", note.getId());
            redisService.setCacheMap(key, map);


        }
        return key;
    }
}
